﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

namespace SsTool.Controls.Workflow
{
    /// <summary>
    /// Interaction logic for ActivityPanel.xaml
    /// </summary>
    public partial class ActivityPanel : UserControl
    {
        // ↑
        public ActivityPanel ParentPanel { get; set; }
        // ←
        public ActivityPanel ForwardPanel { get; set; }
        // →
        public ActivityPanel BackwardPanel { get; set; }

        public double LeftX { get; set; }
        public double RightX { get; set; }
        public double TopY { get; set; }
        public double BottomY { get; set; }

        public List<ActivityPanel> ChildrenPanels { get; set; }

        public int Depth { get; set; }
        public int Index { get; set; }

        public const int _width = 160;
        private int _widthHalf;
        public const int _height = 130;
        private int _heightHalf;
        private int _space = 30;

        private Point _centerPos;

        public event RoutedEventHandler Click;
        public event MouseButtonEventHandler DoubleClick;

        public ActivityPanel()
        {
            InitializeComponent();

            _widthHalf = _width / 2;
            _heightHalf = _height / 2;

            Width = _width;
            Height = _height;

            _ctlContent.Margin = new Thickness(_space);

            ChildrenPanels = new List<ActivityPanel>();
        }

        #region 向下
        public void UpdateRootPosition(Point centerPos)
        {
            //System.Diagnostics.Debug.WriteLine("-------UpdateRootPosition-----" + _ctlContent.Content + "----");
            SetCenterPos(centerPos);

            Queue<ActivityPanel> panels = new Queue<ActivityPanel>();

            foreach (ActivityPanel child in ChildrenPanels)
            {
                panels.Enqueue(child);
            }

            while (panels.Count > 0)
            {
                ActivityPanel curPanel = panels.Dequeue();
                curPanel.UpdateFromParent(curPanel.ParentPanel, curPanel.ParentPanel.GetCenterPos(), curPanel.ParentPanel.ChildrenPanels.Count);
                foreach (ActivityPanel child in curPanel.ChildrenPanels)
                {
                    panels.Enqueue(child);
                }
            }
        }

        private void UpdateFromParent(ActivityPanel parent, Point pCenterPos, double count)
        {
            //System.Diagnostics.Debug.WriteLine("-------UpdateFromParent-----" + _ctlContent.Content + "----");
            double dx = pCenterPos.X + (Index - ((count - 1) / 2)) * _width;
            double dy = pCenterPos.Y + _height;
            Point centerPos = new Point(dx, dy);
            SetCenterPos(centerPos);
        }

        #endregion

        public bool Backup()
        {
            //System.Diagnostics.Debug.WriteLine("-------Backup-----" + _ctlContent.Content + "----");
            Stack<ActivityPanel> panels = new Stack<ActivityPanel>();

            foreach (ActivityPanel child in ChildrenPanels)
            {
                panels.Push(child);
            }

            while (panels.Count > 0)
            {
                ActivityPanel child = panels.Pop();
                if (child.ChildrenPanels.Count == 0)
                {
                    child.ParentPanel.UpdateFromChild(child, child.LeftX, child.RightX, child.TopY, child.BottomY);
                }
                else
                {
                    foreach (ActivityPanel c in child.ChildrenPanels)
                    {
                        panels.Push(c);
                    }
                }
            }

            bool result = true;
            if (ForwardPanel != null && LeftX < ForwardPanel.RightX)
            {
                //System.Diagnostics.Debug.WriteLine("------Forward-" + _ctlContent.Content + "->" + ForwardPanel._ctlContent.Content);
                double dx = (LeftX - ForwardPanel.RightX);
                ActivityPanel p = ForwardPanel;
                while (p != null)
                {
                    p.Move(dx, 0);
                    p = p.CheckForwardRange();
                }
                result = false;
            }

            if (BackwardPanel != null && RightX > BackwardPanel.LeftX)
            {
                //System.Diagnostics.Debug.WriteLine("------Backward-" + _ctlContent.Content + "->" + BackwardPanel._ctlContent.Content);
                double dx = RightX - BackwardPanel.LeftX;
                ActivityPanel p = BackwardPanel;
                while (p != null)
                {
                    p.Move(dx, 0);
                    p = p.CheckBackwardRange();
                }
                result = false;
            }
            return result;
        }

        private void UpdateFromChild(ActivityPanel child, double leftX, double rightX, double topY, double bottomY)
        {
            //System.Diagnostics.Debug.WriteLine("-------UpdateFromChild-----" + _ctlContent.Content + "----");
            if (leftX < LeftX)
            {
                LeftX = leftX;
            }
            else if (rightX > RightX)
            {
                RightX = rightX;
            }
            if (topY < TopY)
            {
                TopY = topY;
            }
            if (bottomY > BottomY)
            {
                BottomY = bottomY;
            }

            if (ParentPanel != null)
            {
                ParentPanel.UpdateFromChild(this, LeftX, RightX, TopY, BottomY);
            }
        }

        private ActivityPanel CheckForwardRange()
        {
            if (ForwardPanel != null && this.LeftX < ForwardPanel.RightX)
            {
                return ForwardPanel;
            }
            return null;
        }

        private ActivityPanel CheckBackwardRange()
        {
            if (BackwardPanel != null && this.RightX > BackwardPanel.LeftX)
            {
                return BackwardPanel;
            }
            return null;
        }

        #region 单向
        public void UpdatePositionOneWay(Point centerPos)
        {
            //System.Diagnostics.Debug.WriteLine("-------UpdatePositionOneWay-----" + _ctlContent.Content + "----");
            Canvas.SetTop(this, centerPos.Y - _heightHalf);
            Canvas.SetLeft(this, centerPos.X - _widthHalf);
            LeftX = centerPos.X - _widthHalf;
            RightX = centerPos.X + _widthHalf;
            TopY = centerPos.Y - _heightHalf;
            BottomY = centerPos.Y + _heightHalf;

            if (ParentPanel != null)
            {
                ParentPanel.UpdateFromChild(this, LeftX, RightX, TopY, BottomY);
            }

            foreach (ActivityPanel child in ChildrenPanels)
            {
                child.UpdateFromParentOneWay(this, centerPos, ChildrenPanels.Count);
            }
        }

        private void UpdateFromParentOneWay(ActivityPanel parent, Point pCenterPos, double count)
        {
            //System.Diagnostics.Debug.WriteLine("-------UpdateFromParentOneWay-----" + _ctlContent.Content + "----");
            double dx = pCenterPos.X + (Index - ((count - 1) / 2)) * _width;
            double dy = pCenterPos.Y + _height;
            Point centerPos = new Point(dx, dy);

            Canvas.SetTop(this, centerPos.Y - _heightHalf);
            Canvas.SetLeft(this, centerPos.X - _widthHalf);
            LeftX = centerPos.X - _widthHalf;
            RightX = centerPos.X + _widthHalf;
            TopY = centerPos.Y - _heightHalf;
            BottomY = centerPos.Y + _heightHalf;

            foreach (ActivityPanel child in ChildrenPanels)
            {
                child.UpdateFromParentOneWay(this, centerPos, ChildrenPanels.Count);
            }
        }
        #endregion

        public void Move(double dx, double dy)
        {
            Point centerPos = new Point(
                _centerPos.X + dx,
                _centerPos.Y + dy);
            this.SetCenterPos(centerPos);
            foreach (ActivityPanel child in ChildrenPanels)
            {
                child.Move(dx, dy);
            }

            if (ParentPanel != null)
            {
                ParentPanel.UpdateFromChild(this, LeftX, RightX, TopY, BottomY);
            }
        }

        public void AllMove(double dx, double dy)
        {
            Point centerPos = new Point(
                _centerPos.X + dx,
                _centerPos.Y + dy);
            this.SetCenterPos(centerPos);
            foreach (ActivityPanel child in ChildrenPanels)
            {
                child.AllMove(dx, dy);
            }
            UpdateRange(this, LeftX, RightX, TopY, BottomY);
        }

        private void UpdateRange(ActivityPanel child, double leftX, double rightX, double topY, double bottomY)
        {
            //System.Diagnostics.Debug.WriteLine("-------UpdateFromChild-----" + _ctlContent.Content + "----");
            if (leftX < LeftX)
            {
                LeftX = leftX;
            }
            else if (rightX > RightX)
            {
                RightX = rightX;
            }
            if (topY < TopY)
            {
                TopY = topY;
            }
            if (bottomY > BottomY)
            {
                BottomY = bottomY;
            }

            if (ParentPanel != null)
            {
                ParentPanel.UpdateRange(this, LeftX, RightX, TopY, BottomY);
            }
        }

        public Point GetCenterPos()
        {
            return _centerPos;
        }

        public void SetCenterPos(Point centerPos)
        {
            _centerPos = centerPos;
            Canvas.SetTop(this, _centerPos.Y - _heightHalf);
            Canvas.SetLeft(this, _centerPos.X - _widthHalf);
            LeftX = _centerPos.X - _widthHalf;
            RightX = _centerPos.X + _widthHalf;
            TopY = _centerPos.Y - _heightHalf;
            BottomY = _centerPos.Y + _heightHalf;
        }

        public Point GetOutPos()
        {
            return new Point(
                Canvas.GetLeft(this) + _widthHalf,
                Canvas.GetTop(this) + _height - _space);
        }

        public Point GetInPos()
        {
            return new Point(
                Canvas.GetLeft(this) + _widthHalf,
                Canvas.GetTop(this) + _space);
        }

        public void SetParent(ActivityPanel parent)
        {
            this.ParentPanel = parent;
            if (parent.ChildrenPanels != null && parent.ChildrenPanels.Count > 0)
            {
                this.ForwardPanel = parent.ChildrenPanels[parent.ChildrenPanels.Count - 1];
                this.ForwardPanel.BackwardPanel = this;
            }
            parent.ChildrenPanels.Add(this);
        }

        private void Button_Click(object sender, RoutedEventArgs e)
        {
            if (Click != null)
            {
                Click(this, e);
            }
        }

        internal void MoveCenter()
        {
            Point cp = GetCenterPos();
            _centerPos = new Point(LeftX + (RightX - LeftX) / 2, cp.Y);
            Canvas.SetTop(this, _centerPos.Y - _heightHalf);
            Canvas.SetLeft(this, _centerPos.X - _widthHalf);

        }

        private void _ctlContent_MouseDoubleClick(object sender, MouseButtonEventArgs e)
        {
            if (DoubleClick != null)
            {
                DoubleClick(this, e);
            }
        }
    }
}
